home *** CD-ROM | disk | FTP | other *** search
- #include "GifScan.h"
- #include "Prefs.h"
- #include "DSUtils.h"
-
- // GIFSCAN - scans through a GIF file and reports all parameters
-
- #include <stdio.h>
-
- enum GIFErrors { kCorruptMessage = 7 };
-
- extern thePrefsHandle gPrefs;
- extern Boolean gCmdHeldDown;
-
- static Boolean showAll, isGIF;
- static char *textBuffer;
- static long bufCounter;
-
- // Function prototypes
- int UnixMain(int, char **);
- void ColorMap(int, FILE *, int);
- void ExtensionInfo(FILE *);
- void CheckUnexpected(int *, int);
- void GetImageInfo(FILE *, int, int);
- unsigned int GetBytes(FILE *);
-
- #define kTempBufferSize 6000L
- #define MAX 255
-
- //**********************************************************************
- // MAIN - the main routine reads the GIF file for the global GIF
- // information which it displays to the user's screen. This
- // routine also determines which subroutine to call and which
- // information to process.
- //**********************************************************************
-
- #define DECIMAL 1
- #define PERCENT 2
- #define HEXIDEC 3
-
- static void CopyHTMLTagToClipboard(void)
- {
- // Find the tag by scanning through the textbuffer...
- short i;
- short start, end;
- long err;
-
- i = 1;
- while ( textBuffer[i] != '<' )
- {
- i++;
- }
- start = i;
- while ( textBuffer[i] != '>' )
- {
- i++;
- }
- end = i;
-
- ZeroScrap();
- err = PutScrap(1 + end - start, 'TEXT', &textBuffer[start]);
- }
-
- static void CreateBuffer(void)
- {
- textBuffer = NewPtr(kTempBufferSize); // 6000 bytes should be enough....
- bufCounter = 0L;
- }
-
- static void DestroyBufferAndCopy(void)
- {
- TEHandle te;
- static short numLines;
-
- if ( (*gPrefs)->copy && isGIF ) CopyHTMLTagToClipboard();
-
- te = ((DocumentPeek)gOutWindow)->docTE;
- numLines = (*te)->nLines;
-
- if ( bufCounter + (*te)->teLength > kMaxTELength )
- {
- // exceeded TE 32k limit -> remove data from the text
- TESetSelect(0L, kTempBufferSize, te);
- TEDelete(te);
- }
- TESetSelect(kMaxTELength, kMaxTELength, te); // Insert at end of text
- TEInsert(textBuffer+1, bufCounter, te); // Avoid garbage at 0
-
- // Scroll down to show the last item opened
- numLines = (*te)->nLines - numLines;
- TEScroll(0, -numLines * (*te)->lineHeight, te);
- AdjustScrollbars(gOutWindow, false);
- AdjustTE(gOutWindow);
-
- // Dispose of the buffer
- DisposePtr(textBuffer);
- }
-
- // Inspired by Paul Dubois TransDisplay
- static void DisplayText(Ptr theText, long len)
- {
- BlockMoveData(theText, textBuffer + bufCounter + 1, len);
- bufCounter += len;
- // Originally, this called TEInsert immediately, way too slow
- }
-
- static void DisplayString (StringPtr str)
- {
- DisplayText ((Ptr) (str+1), (long) str[0]);
- }
-
- static void DisplayCString (char *str)
- {
- long len = 0;
- char *s;
-
- for (s = str; *s != '\0'; s++)
- ++len;
- DisplayText ((Ptr) str, len);
- }
-
- static void DisplayChar (short c)
- {
- char ch = c;
-
- DisplayText (&ch, 1L);
- }
-
- static void DisplayLong (long l, Boolean table)
- {
- Str255 s, space;
-
- NumToString (l, s);
- if ( table )
- {
- // Textedit does not support tabs so must come up with something else
- // to make a table look like something...
- // This is very custom to this application
- if ( l < 10 )
- {
- pcpy(space, "\p ");
- pcat(space, s);
- pcpy(s, space);
- }
- if ( l < 100 )
- {
- pcpy(space, "\p ");
- pcat(space, s);
- pcpy(s, space);
- }
- }
- DisplayString (s);
- }
-
- static void DisplayShort (short i, Boolean table)
- {
- DisplayLong ((long) i, table);
- }
-
- static void DisplayLn (void)
- {
- DisplayChar ('\r');
- }
-
- static void HexByte (short value) // should be 0..15
- {
- DisplayChar ((char) (value + (value < 10 ? '0' : 'A' - 10)));
- }
-
- static void DisplayHexChar (short c)
- {
- HexByte ((short) (c >> 4) & 0x0f);
- HexByte ((short) c & 0x0f);
- }
-
- // From MoreFiles 1.3
- static OSErr GetFilenameFromPathname(ConstStr255Param pathname, Str255 filename)
- {
- short index;
- short nameEnd;
-
- filename[0] = 0;
-
- if ( pathname == nil ) return ( notAFileErr );
-
- index = pathname[0];
-
- if ( index == 0 ) return ( notAFileErr );
-
- if ( pathname[index] == ':' )
- --index;
-
- nameEnd = index;
-
- if ( pathname[index] == ':' ) return ( notAFileErr );
-
- while ( (index != 0) && (pathname[index] != ':') )
- {
- --index;
- }
-
- if ( (index == 0) && (pathname[pathname[0]] == ':') )
- return ( notAFileErr );
-
- filename[0] = (char)(nameEnd - index);
- BlockMoveData(&pathname[index+1], &filename[1], nameEnd - index);
- return ( noErr );
- }
-
- int UnixMain(int argc, char **argv)
- {
- char version[7];
-
- Str255 fileName;
-
- int byte1;
- int byte2;
- int byte3;
- int colorResolution;
- int unexpected;
- int imageCount;
- int bitsPerPix;
- int bitsToUse;
- int colors;
- int i, n;
- int globl;
- int endOfGifFound;
- int colorStyle;
-
- unsigned int width;
- unsigned int height;
-
- FILE *in;
-
- // Start of Processing
- SetCursor(*GetCursor(watchCursor));
- colorStyle = 0;
-
- if ( (*gPrefs)->hexadecimal ) colorStyle = HEXIDEC;
- if ( (*gPrefs)->decimal ) colorStyle = DECIMAL;
- if ( (*gPrefs)->percentages ) colorStyle = PERCENT;
-
- if ( (*gPrefs)->forget && gCmdHeldDown )
- showAll = true;
- else if ( (*gPrefs)->forget && !gCmdHeldDown )
- showAll = false;
- else if ( !(*gPrefs)->forget && gCmdHeldDown )
- showAll = false;
- else
- showAll = true;
-
- for ( n = 1; n < argc; n++ )
- {
- in = fopen(argv[n], "rb");
-
- imageCount = 0;
- endOfGifFound = 0;
- unexpected = 0;
-
- CreateBuffer();
-
- // Print name of the inputfile
- if ( showAll )
- {
- DisplayString("\pFilename: ");
- DisplayCString(argv[n]);
- DisplayLn();
- }
-
- // get version from file
- if ( ( version[0] = getc(in) ) == 0x47 )
- {
- isGIF = true;
-
- for (i = 1; (i < 6); i++)
- version[i] = getc(in);
- version[6] = '\0';
- if ( showAll )
- {
- DisplayString("\pGIF Version: ");
- DisplayCString(version);
- DisplayLn();
- }
-
- // determine image width
- width = GetBytes(in);
-
- // determine image height
- height = GetBytes(in);
-
- if ( showAll )
- {
- // General
- DisplayString("\pImage Height: ");
- DisplayShort(height, false);
- DisplayString("\p Image Width: ");
- DisplayShort(width, false);
- DisplayLn(); DisplayLn();
- }
-
- // HTML specification, show always
- DisplayString("\p<IMG SRC=\"");
- if ( (*gPrefs)->fullPath )
- {
- DisplayCString(argv[n]);
- }
- else
- {
- c2p(argv[n]);
- GetFilenameFromPathname((ConstStr255Param)argv[n], fileName);
- DisplayString(fileName);
- p2c((StringPtr)argv[n]);
- }
- DisplayString("\p\" ");
- DisplayString("\pALT=\"\"");
- DisplayString("\p HEIGHT=");
- DisplayShort(height, false);
- DisplayString("\p WIDTH=");
- DisplayShort(width, false);
- DisplayString("\p>");
-
- if ( showAll)
- {
- DisplayLn(); DisplayLn();
- }
-
- // check for a Global Map
- byte1 = getc(in);
- byte2 = byte1 & 0x80;
- if ( byte2 == 0x80 )
- {
- if ( showAll )
- {
- DisplayString("\pGlobal Color Map: Yes");
- DisplayLn();
- }
- globl = 1;
- }
- else
- {
- if ( showAll )
- {
- DisplayString("\pGlobal Color Map: No");
- DisplayLn();
- }
- globl = 0;
- }
-
- // Check for the 0 bit
-
- byte2 = byte1 & 0x08;
- if ( byte2 != 0 )
- {
- if ( showAll )
- {
- DisplayString("\p? -- Reserved zero bit is not zero.");
- DisplayLn();
- }
- }
-
- // determine the color resolution
- byte2 = byte1 & 0x70;
- colorResolution = byte2 >> 4;
-
- // get the background index
- byte3 = getc(in);
- if ( showAll )
- {
- DisplayString("\pColor res: ");
- DisplayShort(++colorResolution, false);
- DisplayString("\p Background index: ");
- DisplayLong(byte3, false);
- DisplayLn(); DisplayLn();
- }
-
- // determine the bits per pixel
- bitsPerPix = byte1 & 0x07;
- bitsPerPix++;
- bitsToUse = bitsPerPix;
-
- // determine # of colors in global map
- colors = 1 << bitsPerPix;
- if ( showAll )
- {
- DisplayString("\pBits per pixel: ");
- DisplayShort(bitsPerPix, false);
- DisplayString("\p Colors: ");
- DisplayShort(colors, false);
- DisplayLn();
- }
-
- // check for the 0 byte
- byte1 = getc(in);
- if ( byte1 != 0 )
- {
- if ( showAll )
- {
- DisplayString("\p? -- Reserved byte after Background index is not zero.");
- DisplayLn();
- }
- }
-
- ColorMap (colorStyle, in, colors);
-
- // check for the zero byte count, a new image, or the end marker for the gif file
- while ( ( byte1 = getc(in) ) != EOF )
- {
- if ( byte1 == ',' )
- {
- imageCount++;
- if (unexpected != 0) CheckUnexpected(&unexpected, imageCount);
- GetImageInfo(in, bitsToUse, colorStyle);
- }
- else if (byte1 == '!')
- ExtensionInfo (in);
- else if (byte1 == ';')
- {
- if (unexpected != 0) CheckUnexpected(&unexpected, -1);
- endOfGifFound = 1;
- }
- else
- unexpected++;
- }
-
- // EOF has been reached - check last bytes read
- if (endOfGifFound == 0)
- {
- if (showAll)
- {
- DisplayString("\p? -- GIF file terminator ';' was not found.");
- DisplayLn();
- }
- }
- else if (unexpected != 0)
- CheckUnexpected(&unexpected, -2);
- }
- else
- {
- isGIF = false;
- if ( !showAll )
- {
- DisplayString("\pFilename: ");
- DisplayCString(argv[n]);
- DisplayLn();
- }
- DisplayString("\p...Is probably NOT a GIF file!!!");
- DisplayLn();
- if ( showAll ) DisplayLn();
- }
- clearerr(in);
- fclose(in);
-
- if ( showAll )
- {
- DisplayString("\p-----------------------------------------");
- DisplayLn(); DisplayLn();
- }
- DestroyBufferAndCopy();
- }
-
- SetCursor(&qd.arrow);
- // Reset this global to false
- gCmdHeldDown = false;
- }
-
- //**********************************************************************
- // COLORMAP - reads color information in from the GIF file and displays
- // it in a user selected method. This display may be in :
- // hexidecimal (default), percentage, or decimal. User
- // selects output method by placing a switch (-d, -p, -h)
- // between the program name and GIF filename at request time.
- //**********************************************************************
-
- void ColorMap(int out, FILE *dev, int times)
- {
- unsigned int red;
- unsigned int green;
- unsigned int blue;
-
- int printCount;
- int i;
-
- // Start of procedure
-
- if ( (*gPrefs)->showColors || gCmdHeldDown )
- {
- DisplayLn();
- if (out == DECIMAL)
- {
- if ( showAll )
- DisplayString("\pColor definitions in decimal (index # R, G, B)");
- }
-
- if (out == PERCENT)
- {
- if ( showAll )
- DisplayString("\pColor definitions by percentage (index # R, G, B)");
- }
-
- if (out == HEXIDEC)
- {
- if ( showAll )
- DisplayString("\pColor definitions by hexidecimal (index # R, G, B)");
- }
- DisplayLn();
-
- // read and print the color definitions
- printCount = 0;
-
- for (i = 0; (i < times); i++)
- {
- red = getc(dev);
- green = getc(dev);
- blue = getc(dev);
-
- switch (out)
- {
- case DECIMAL :
- if ( showAll )
- {
- DisplayShort(i, true);
- DisplayString("\p - ");
- DisplayShort(red, true);
- DisplayString("\p ");
- DisplayShort(green, true);
- DisplayString("\p ");
- DisplayShort(blue, true);
- DisplayString("\p ");
- }
- break;
-
- case PERCENT :
- red = (red * 100) / MAX;
- green = (green * 100) / MAX;
- blue = (blue * 100) / MAX;
- if ( showAll )
- {
- DisplayShort(i, true);
- DisplayString("\p - ");
- DisplayShort(red, true);
- DisplayString("\p ");
- DisplayShort(green, true);
- DisplayString("\p ");
- DisplayShort(blue, true);
- DisplayString("\p ");
- }
- break;
-
- case HEXIDEC :
- if ( showAll )
- {
- DisplayShort(i, true);
- DisplayString("\p - ");
- DisplayHexChar(red);
- DisplayString("\p ");
- DisplayHexChar(green);
- DisplayString("\p ");
- DisplayHexChar(blue);
- DisplayString("\p ");
- }
- break;
- }
-
- printCount++;
- if (printCount == 4)
- {
- if ( showAll ) DisplayLn();
- printCount = 0;
- }
- }
-
- if ((times % 4) != 0)
- if ( showAll ) DisplayLn();
- }
- else
- {
- // No feedback to screen
- printCount = 0;
- for (i = 0; (i < times); i++)
- {
- red = getc(dev);
- green = getc(dev);
- blue = getc(dev);
- printCount++;
- if (printCount == 4) printCount = 0;
- }
- }
- }
-
- //**********************************************************************
- // GETBYTES - routine to retrieve two bytes of information from the GIF
- // file and then shift them into correct byte order. The
- // information is stored in Least Significant Byte order.
- //**********************************************************************
-
- unsigned int GetBytes(FILE *dev)
- {
- int byte1;
- int byte2;
- int result;
-
- // read bytes and shift over
- byte1 = getc(dev);
- byte2 = getc(dev);
-
- result = (byte2 << 8) | byte1;
-
- return result;
- }
-
-
- //**********************************************************************
- // IMAGEINF - routine to read the GIF image information and display it
- // to the user's screen in an orderly fashion. If there are
- // multiple images then IMAGEINF will be called to display
- // multiple screens.
- //**********************************************************************
-
- void GetImageInfo(FILE *dev, int bitsToUse, int colorStyle)
- {
- int byte1;
- int byte2;
- int imageLeft;
- int imageTop;
- int dataByteCount;
- int bitsPerPix;
- int colors;
- int i;
- int local;
-
- unsigned int width;
- unsigned int height;
-
- unsigned long bytetot;
- unsigned long possbytes;
-
- // determine the image left value
- imageLeft = GetBytes(dev);
-
- // determine the image top value
- imageTop = GetBytes(dev);
-
- // determine the image width
- width = GetBytes(dev);
-
- // determine the image height
- height = GetBytes(dev);
-
- // check for interlaced image
- byte1 = getc(dev);
- byte2 = byte1 & 0x40;
- if ( byte2 == 0x40 )
- {
- if (showAll)
- {
- DisplayLn();
- DisplayString("\pInterlaced: Yes");
- DisplayLn();
- }
- }
- else
- {
- if (showAll)
- {
- DisplayLn();
- DisplayString("\pInterlaced: No");
- DisplayLn();
- }
- }
-
- // check for a local map
- byte2 = byte1 & 0x80;
- if ( byte2 == 0x80 )
- {
- local = 1;
- if (showAll)
- {
- DisplayString("\pLocal Color Map: Yes");
- DisplayLn();
- }
- }
- else
- {
- local = 0;
- if (showAll)
- {
- DisplayString("\pLocal Color Map: No");
- DisplayLn();
- }
- }
-
- // check for the 3 zero bits
- byte2 = byte1 & 0x38;
- if ( byte2 != 0 )
- {
- if (showAll)
- {
- DisplayString("\p? -- Reserved zero bits in image not zeros.");
- DisplayLn();
- }
- }
-
- // determine the # of color bits in local map
- bitsPerPix = byte1 & 0x07;
- bitsPerPix++;
- colors = 1 << bitsPerPix;
-
- if ( local == 1 )
- {
- bitsToUse = bitsPerPix;
- if (showAll)
- {
- DisplayString("\pBits per pixel: ");
- DisplayShort(bitsPerPix, false);
- DisplayString("\p Colors: ");
- DisplayShort(colors, false);
- DisplayLn();
- }
- if ( (*gPrefs)->showColors || gCmdHeldDown ) ColorMap (colorStyle, dev, colors);
- }
-
- // retrieve the code size
- byte1 = getc(dev);
- if ( (byte1 < 2) || (byte1 > 8) )
- {
- if (showAll)
- {
- DisplayString("\p? -- Code size ");
- DisplayLong(byte1, false);
- DisplayString("\p at start of image is out of range (2-8).");
- DisplayLn();
- }
- }
- else
- {
- if (showAll)
- {
- DisplayString("\pLZW min code size (bits): ");
- DisplayLong(byte1, false);
- DisplayLn();
- }
- }
-
- // tally up the total bytes and read past each data block
- bytetot = 0;
- possbytes = 0;
-
- while ( ( dataByteCount = getc(dev) ) > 0)
- {
- bytetot = bytetot + dataByteCount;
- for ( i = 0; (i < dataByteCount); i++ )
- {
- byte2 = getc(dev);
- if ( byte2 == EOF )
- {
- if ( showAll )
- {
- DisplayString("\p? -- EOF reached inside image data block.");
- DisplayLn();
- }
- ErrorAlert(kErrStringID, kCorruptMessage, 12915, true);
- }
- }
- }
-
- possbytes = (unsigned long) width * height;
- i = 8 / bitsToUse;
- possbytes = possbytes / i;
- if ( showAll )
- {
- DisplayString("\pTotal bytes: ");
- DisplayLong(bytetot, false);
- DisplayString("\p out of possible ");
- DisplayLong(possbytes, false);
- DisplayString("\p.");
- DisplayLn();
- }
-
- if ( dataByteCount == EOF )
- {
- if (showAll)
- {
- DisplayString("\p? -- EOF reached before zero byte count of image was read.");
- DisplayLn();
- }
- ErrorAlert(kErrStringID, kCorruptMessage, 12916, true);
- }
- }
-
-
-
- //**********************************************************************
- // EXTNINFO - routine to read the GIF file for extension data and
- // display it to the screen in an orderly fasion. This
- // extension information may be located before, between, or
- // after any of the image data.
- //**********************************************************************
-
- void ExtensionInfo(FILE *dev)
- {
- int byte1;
- int byte2;
- int i;
- int dataByteCount;
-
- unsigned long bytetot;
-
- // retrieve the function code
-
- byte1 = getc(dev);
- if ( showAll )
- {
- DisplayLn();
- DisplayString("\pGIF extension seen, code : ");
- DisplayLong(byte1, false);
- DisplayLn();
- }
-
- // tally up the total bytes and read past each data block
- bytetot = 0;
-
- while ( ( dataByteCount = getc(dev) ) > 0 )
- {
- bytetot = bytetot + dataByteCount;
- for (i = 0; (i < dataByteCount); i++)
- {
- byte2 = getc(dev);
- if (byte2 == EOF)
- {
- if ( showAll )
- {
- DisplayString("\p? -- EOF reached inside extension data block.");
- DisplayLn();
- }
- ErrorAlert(kErrStringID, kCorruptMessage, 12917, true);
- }
- }
- }
-
- if ( showAll )
- {
- DisplayString("\pTotal number of bytes in extension: ");
- DisplayLong(bytetot, false);
- DisplayLn();
- }
-
- if (dataByteCount == EOF)
- {
- if ( showAll )
- {
- DisplayString("\p? -- EOF was reached before zero byte count of extension was read.");
- DisplayLn();
- }
- ErrorAlert(kErrStringID, kCorruptMessage, 12917, true);
- }
- }
-
-
- //**********************************************************************
- // CHKUNEXP - routine to check for any unexpected nonzero data found
- // within the GIF file. This routine will help determine
- // where the unexpected data may reside in the file.
- //**********************************************************************
-
- void CheckUnexpected (int *unexpected, int determiner)
- {
- // Determine place in the GIF file
-
- if ( determiner > 0 )
- {
- if ( showAll )
- {
- DisplayString("\p? -- ");
- DisplayLong(*unexpected, false);
- DisplayString("\p bytes of unexpected data found before image ");
- DisplayLong(determiner, false);
- DisplayString("\p.");
- DisplayLn();
- }
- }
- else if ( determiner == -1 )
- {
- if ( showAll )
- {
- DisplayString("\p? -- ");
- DisplayLong(*unexpected, false);
- DisplayString("\p bytes of unexpected data found before GIF file terminator.");
- DisplayLn();
- }
- }
- else
- {
- if ( showAll )
- {
- DisplayString("\p? -- ");
- DisplayLong(*unexpected, false);
- DisplayString("\p bytes of unexpected data found after GIF file terminator.");
- DisplayLn();
- }
- }
-
- // Zero out unexpected variable for next group that may be encountered
- *unexpected = 0;
- }
-
- /************************************************************************
- Name and address of the original author (1989!!):
-
- jdm@hodge.cts.com [uunet zardoz vdelta crash]!hodge!jdm
-
- James D. Murray, Ethnounixologist
- Hodge Computer Research Corporation
- 1588 North Batavia Street
- Orange, California 92667 USA
-
- TEL: (714) 998-7750 Ask for James
- FAX: (714) 921-8038 Wait for the carrier
- ************************************************************************/
-